//(function($) {

	empty = function(val) {
		return (typeof(val) === "undefined" || val===null || val===false || val===0 || val==='' || (jQuery.isArray(val) && val.length==0) || jQuery.isEmptyObject(val));
	};
	
	Matrix = function(matrix) {
		this.matrix = matrix;
		this._fix();
	};
	
	Matrix.prototype = {
		empty: 0,
		
		clone: function() {
			return new Matrix(JSON.parse(JSON.stringify(this.matrix)));
		},
		
		width: function(idx) {
			return this.matrix[empty(idx) ? 0 : idx].length;
		},
		
		height: function() {
			return this.matrix.length;
		},
		
		_fix: function() {
			// process matrix
			var _max = 0;
			for(var r=0; r<this.height(); r++) {
				_max = Math.max(_max, this.width(r));
			}
			
			for(var r=0; r<this.height(); r++) {
				// Fill empty spaces. Make matrix rectangular.
				var _dif = _max - this.width(r);
				
				if(_dif>0)	console.info(this, "Expanding row "+r);
				
				for(var s=0; s<_dif; s++)
					this.matrix[r].push(this.empty);
			}
		},
		
		line: function(idx, isVLine) {
			if(empty(isVLine)) {
				return jQuery.extend([], this.matrix[idx]);				
			} else {
				var line = [];
				for(var r=0; r<this.height(); r++)
					line.push(this.matrix[r][idx]);
				return line;
			}
		},

		insertLine: function(idx, line, isVLine) {
			if(empty(isVLine)) {
				if(line.length != this.width()) console.warn("Matrix:", "Not valid line!");
				this.matrix.splice(idx, 0, line);
			} else {
				if(line.length != this.height()) console.warn("Matrix:", "Not valid line!");
				for(var r=0; r<this.height(); r++) {
					this.matrix[r].splice(idx, 0, line[r]);
				}
			}
		},
		
		removeLine: function(idx, isVLine) {
			if(empty(isVLine)) {
				this.matrix.splice(idx, 1);
			} else {
				for(var r=0; r<this.height(); r++) {
					this.matrix[r].splice(idx, 1);
				}
			}
		},
		
		rotate: function() {
			var _newMatrix = [];
			for(var c=0; c<this.width(); c++) {
				var _line = this.line(c, true);
				_line.reverse();
				_newMatrix.push(_line);
			}
			this.matrix = _newMatrix;
		}
	};

	MPLayoutObject = function(options) {
		jQuery.extend(this, {
			position: { left: 0, top: 0 },
			size: { width: 0, height: 0 },
			pattern: '#ffeedd'
			uid: null,
            //type: 0,
			isRound: false,
			isTable: false,
			scheme: [],
			title: "",
			sits: []
		});
		jQuery.extend(this, options);
		
		if(jQuery.isArray(this.scheme)) {
			this.scheme = new Matrix(this.scheme);
			this._validateScheme();
		}
	};
	
	MPLayoutObject.prototype = {
		placeSize: 54,
		table: 1,
		resizer: 2,
		empty: 0,
		nonplace: 3,
		
		serialize: function() {
			if(this.scheme instanceof Matrix)
				this.scheme = this.scheme.matrix;
			return JSON.parse(JSON.stringify(this));
		},
		
		deserialize: function(obj) {
			return new MPLayoutObject(obj);
		},
		
		clone: function() {
			var _clone = this.serialize();
			return this.deserialize(_clone);
		},
		
		_validateScheme: function(){			
			// Duplicate resizers for rotations
			for(var r=0; r<this.scheme.height(); r++) {
				if(this.scheme.matrix[r][0] == this.resizer && this.scheme.matrix[r][this.scheme.width()-1]==0)
					this.scheme.matrix[r][this.scheme.width()-1] = this.resizer;
			}
			for(var c=0; c<this.scheme.width(); c++) {
				if(this.scheme.matrix[0][c] == this.resizer && this.scheme.matrix[this.scheme.height()-1][c]==0)
					this.scheme.matrix[this.scheme.height()-1][c] = this.resizer;
			}
		},
		
		_getTableResizers: function(isVert) {
			var _indexes = [];
			var _line = this.scheme.line(0, isVert);
			for(var i=0; i<_line.length; i++) {
				if(_line[i] == this.resizer)
					_indexes.push(i);
			}
			return _indexes;
		},
		
		_getMatrixPos: function(){
			var _placeHolders = [];
			var _tables = [];
			var _grid = this.scheme.matrix;
			
			for(var i=0; i<this.scheme.height(); i++) {
				for(var j=0; j<this.scheme.width(); j++) {
					if(_grid[i][j] == this.table) {
						_tables.push({y: i, x: j});
						continue;
					}
					else if(_grid[i][j] != this.nonplace) {
						if( typeof(_grid[i-1])!="undefined" && _grid[i-1][j] == this.table 
							|| typeof(_grid[i+1])!="undefined" && _grid[i+1][j] == this.table
							|| typeof(_grid[i][j-1])!="undefined" && _grid[i][j-1] == this.table
							|| typeof(_grid[i][j+1])!="undefined" && _grid[i][j+1] == this.table) {
							
							_placeHolders.push({y: i, x: j});
						}
					}
				}
			}
			return {tables: _tables, placeholders: _placeHolders};
		}, 
		
		getPlaceHolders: function() {
			return this._getMatrixPos().placeholders;
		},
		
		getTables: function() {
			return this._getMatrixPos().tables;
		},
		
		getTableBounds: function()  {
			var bounds = { left: 0, top: 0, width: 0, height: 0};
			var tables = this.getTables();
			
			var hor = [];
			var ver = [];
			
			for(var i=0; i<tables.length; i++) {
				ver.push(tables[i].y);
				hor.push(tables[i].x);
			}
			
			bounds.left = Math.min.apply(Math, hor);
			bounds.top = Math.min.apply(Math, ver);
			bounds.width = (Math.max.apply(Math, hor)+1) - bounds.left;
			bounds.height = (Math.max.apply(Math, ver)+1) - bounds.top;
			
			return bounds;
		},

		getTableBiggestArea: function()  {
			var area = {left:0, top:0, width:0, height:0};
			
			var lines = [];
			var pos = [];
			var max = 0;
			
			// Get table lines lengths
			for(var r=0; r<this.scheme.height(); r++) {
				lines.push([]);
				pos.push([]);
				var len = 0;
				for(var c=0; c<this.scheme.width(); c++) {
					if(this.scheme.matrix[r][c] == this.table) {
						len++;
					} else {
						max = Math.max(max, len);
						lines[lines.length-1].push(len);
						pos[pos.length-1].push(c);
						len = 0;
					}		
				}
				if(len>0) {
					max = Math.max(max, len);
					lines[lines.length-1].push(len);
					pos[pos.length-1].push(c);
				}
			}

			for(var r=0; r<lines.length; r++) {
				for(var l=0; l<lines[r].length; l++) {
					if(max == lines[r][l]) {
						area.left = pos[r][l]-lines[r][l];
						area.top = r;
						area.width = lines[r][l];
						area.height = 1;
						
						// Get sub area
						for(var n=r+1; n<lines.length; n++) {
							var includeSub = false;
							for(var k=0; k<lines[n].length; k++) {
								if(lines[n][k]>=area.width && pos[n][k]>=pos[r][l] && pos[n][k]-lines[n][k]<=area.left) {
									area.height++;
									includeSub = true;
								}			
							}
							if(!includeSub) break;
						}
						r = lines.length;
						break;
					}
				}
			}
			
			return area;
		},

		_resizeTableScheme: function(size, isVert) {
			var _line = this.scheme.line(0, isVert);

			if(_line.length != size) {
				var _indexes = [], _lastSizers = [];
				
				_indexes = this._getTableResizers(isVert);
				for(var i=0; i<_line.length; i++) {
					if(_line[i] < 0)
						_lastSizers.push(_line[i]);
				}
				
				var _minSizer = Math.min.apply(Math, jQuery.extend([-1], _lastSizers));
				var _offset = 0;
				if(_line.length > size && _lastSizers.length>0) {
					for(var i=0; i<_line.length; i++) {
						if(_line[i] == _minSizer) {
							this.scheme.removeLine(i+_offset, !isVert);
							_offset--;
						}
					}					
				} else if(_line.length < size) {
					for(var i=0; i<_indexes.length; i++) {
						var _lineCpy = this.scheme.line(_indexes[i]+_offset, !isVert);
						_lineCpy[0] = _lineCpy[_lineCpy.length-1] = _minSizer-1;							
						this.scheme.insertLine(_indexes[i]+1+_offset, _lineCpy, !isVert);
						_offset++;
					}
				}
			}
		},
		
		resizeScheme: function(size) {
			
			if(this.isRound && size>=2) {
				this.scheme = size;
			} else if(!this.isRound && this.isTable){
				this._resizeTableScheme(size.width, false);
				this._resizeTableScheme(size.height, true);
			}
		},
		
		rotateScheme: function() {
			this.scheme.rotate();
			
			for(var i=0; i<this.sits.length; i++){
				if(this.sits[i] != null) {
					var _position = { 
							y: this.sits[i].position.x,
							x: this.scheme.width()-1 - this.sits[i].position.y
						};
					
					this.sits[i].position.x = _position.x;
					this.sits[i].position.y = _position.y;
				}
			}
		}		
	};	
	
	MPLayout = function(options) {
		jQuery.extend(this, {viewMode: false, layoutMembers: [], pair: [], guests: []}); 
		
		jQuery.extend(this, options);
	
		this.stage
			.addClass("mp-canvas ui-widget")
			.data("mp-manager", this);
		
		this.toolbar
			.addClass("mp-toolbar ui-accordion ui-widget ui-helper-reset ui-accordion-icons")
			.data("mp-manager", this);

		this._fillToolBar();
		
		if(!this.viewMode) {
			this._bindToolbarEvents();
			
			jQuery( ".mp-draggable li" )
				.css("cursor", "move")
				.hover(function(event){ jQuery(this).addClass("ui-state-active"); }, function(event){ jQuery(this).removeClass("ui-state-active"); });
		}
	};

	MPLayout.prototype = {
	    localization: {
	        current: "ru-RU",
	        "ru-RU": {
	            STAGE_OBJECTS: "Объекты",
	            GUESTS: "Гости",
	            TITLE: "Заголовок",
	            PLACE_COUNT: "Число мест",
	            OK: "ОК",
	            APPLY: "Применить",
	            CANCEL: "Отмена",
	            ACTION_EDIT: "Изменить",
	            ACTION_DELETE: "Удалить",
	            ACTION_DELETE_CONFIRM: "Удалить?",
	            ACTION_ROTATE: "Повернуть",
	            ACTION_ENCREASE: "Увеличить",
	            ACTION_ENCREASE_H: "Увеличить по горизонтали",
	            ACTION_ENCREASE_V: "Увеличить по вертикали",
	            ACTION_REDUCE: "Уменьшить",
	            ACTION_REDUCE_H: "Уменьшить по горизонтали",
	            ACTION_REDUCE_V: "Уменьшить по вертикали"
	        }
	    },

	    // fill toolbar

	    _: function (name) {
	        return this.localization[this.localization.current][name];
	    },

	    _addScroll: function (pane) {
	        //scrollpane parts
	        var scrollPane = pane.find(".mp-wrapper"),
            scrollContent = pane.find(".mp-scroll-content");

	        //build slider
	        var scrollbar = $(".scroll-bar").slider({
	            orientation: "vertical",
	            slide: function (event, ui) {
	                if (scrollContent.height() > scrollPane.height()) {
	                    scrollContent.css("margin-top", Math.round(
                        ui.value / 100 * (scrollPane.height() - scrollContent.height())
                    ) + "px");
	                } else {
	                    scrollContent.css("margin-top", 0);
	                }
	            }
	        });

	        scrollPane.mousewheel(function (e, delta) {
	            e.stopPropagation();
	            //console.log(e);
	        });

	        //append icon to handle
	        var handleHelper = scrollbar.find(".ui-slider-handle")
                .mousedown(function () {
                    // scrollbar.height(handleHelper.height());
                })
                .mouseup(function () {
                    // scrollbar.height("100%");
                })
	        //.append("<span class='ui-icon ui-icon-grip-dotted-horizontal'></span>")
	        //.wrap("<div class='ui-handle-helper-parent'></div>").parent();

	        //change overflow to hidden now that slider handles the scrolling
	        scrollPane.css("overflow", "hidden");

	        //size scrollbar and handle proportionally to scroll distance
	        function sizeScrollbar() {
	            var remainder = scrollContent.width() - scrollPane.width();
	            var proportion = remainder / scrollContent.width();
	            var handleSize = scrollPane.width() - (proportion * scrollPane.width());
	            scrollbar.find(".ui-slider-handle").css({
	                width: handleSize,
	                "margin-left": -handleSize / 2
	            });
	            handleHelper.width("").width(scrollbar.width() - handleSize);
	        }

	        //reset slider value based on scroll content position
	        function resetValue() {
	            var remainder = scrollPane.width() - scrollContent.width();
	            var leftVal = scrollContent.css("margin-left") === "auto" ? 0 :
                parseInt(scrollContent.css("margin-left"));
	            var percentage = Math.round(leftVal / remainder * 100);
	            scrollbar.slider("value", percentage);
	        }

	        //if the slider is 100% and window gets larger, reveal content
	        function reflowContent() {
	            var showing = scrollContent.width() + parseInt(scrollContent.css("margin-left"), 10);
	            var gap = scrollPane.width() - showing;
	            if (gap > 0) {
	                scrollContent.css("margin-left", parseInt(scrollContent.css("margin-left"), 10) + gap);
	            }
	        }

	        //change handle position on window resize
	        $(window).resize(function () {
	            resetValue();
	            sizeScrollbar();
	            reflowContent();
	        });
	        //init scrollbar size
	        setTimeout(sizeScrollbar, 10); //safari wants a timeout
	    },

	    _fillToolBar: function () {


	        var tabPane = new goog.ui.TabPane(goog.dom.$('mp-toolbar'));




	        //this.toolbar
	        //    .append("<ul>");

	        //var $tabs = this.toolbar.children('ul');

	        //$tabs
	        //    .append("<li><a href=\'#tabs-objects\'>" + this._('STAGE_OBJECTS') + "</a></li>")
	        //    .append("<li><a href=\'#tabs-guests\'>" + this._('GUESTS') + "</a></li>");

	        // Fill objects			
	        this.toolbar
				.append("<div id=\'tabs-objects\' class=\'ui-widget mp-pane mp-draggable mp-objects\'><div class=\'mp-wrapper\'><div class=\'mp-scroll-content\'><ul></ul></div><div class=\'scroll-bar-wrap ui-widget-content\'><div class=\'scroll-bar\'></div></div></div></div>");

	        var $ul = this.toolbar.find(".mp-objects ul");

	        for (var i = 0; i < this.layoutMembers.length; i++) {
	            var layoutScheme = this.layoutMembers[i];
	            jQuery("<li/>")
					.addClass("ui-state-default")
					.data("scheme", layoutScheme)
					.appendTo($ul)
					.text(layoutScheme.title);
	        }

	        //this._addScroll(this.toolbar.find(".mp-objects"));

	        // Fill guests
	        this.toolbar
				.append("<div id=\'tabs-guests\' class=\'mp-draggable mp-droppable mp-guests\'><ul></ul></div>");

	        var $ul = this.toolbar.find(".mp-guests ul");

	        for (var i = 0; i < 2; i++) {
	            jQuery("<li/>")
					.addClass("ui-state-default mp-pair mp-draggable-guest")
					.data("data", this.pair[i])
					.appendTo($ul)
					.append(jQuery("<span/>").append(jQuery("<p/>").text(this.pair[i].name)));
	        }

	        for (var i = 0; i < this.guests.length; i++) {
	            jQuery("<li/>")
					.addClass("ui-state-default mp-draggable-guest")
					.data("data", this.guests[i])
					.appendTo($ul)
					.append(jQuery("<span/>").append(jQuery("<p/>").text(this.guests[i].name)));
	        }



	        tabPane.addPage(new goog.ui.TabPane.TabPage(
        document.getElementById('tabs-objects'), this._('STAGE_OBJECTS')));
	        tabPane.addPage(new goog.ui.TabPane.TabPage(
        document.getElementById('tabs-guests'), this._('GUESTS')));
	        tabPane.addPage(new goog.ui.TabPane.TabPage(null, 'Page 3'));
	        tabPane.addPage(new goog.ui.TabPane.TabPage('Page 5'));
	        tabPane.addPage(new goog.ui.TabPane.TabPage('Page 4'), 3);
	        //tabPane.setFocusable(false);
	        tabPane.setSelectedIndex(1);

	        //this.toolbar.tabs();

	        // Process custom accordion
	        /*this.toolbar.find("h3")
	        .click(function () {
	        jQuery(this).next().toggle("blind");
	        jQuery(this).find(".ui-icon").toggleClass("ui-icon-triangle-1-s ui-icon-triangle-1-e");
	        return false;
	        })
	        .addClass("ui-accordion-header ui-helper-reset ui-state-default")
	        .next().addClass("ui-helper-reset").show();
	        */
	    },

	    _sortGuests: function () {
	        var $_guestlist = this.toolbar.find('.mp-guests ul');
	        var $_listitems = $_guestlist.children('li').get();
	        $_listitems.sort(function (a, b) {
	            var compA = jQuery(a).hasClass("mp-pair") ? 1 : 0;
	            var compB = jQuery(b).hasClass("mp-pair") ? 1 : 0;
	            return (compA > compB) ? -1 : (compA < compB) ? 1 : 0;
	        });
	        jQuery.each($_listitems, function (idx, itm) { $_guestlist.append(itm); });
	    },

	    _bindToolbarEvents: function () {

	        jQuery(".mp-draggable.mp-objects li").each(function () {
	            jQuery(this).draggable({
	                revert: "invalid",
	                revertDuration: 0,
	                cursor: "move",
	                appendTo: "body",
	                cursorAt: { left: 50, top: 50 },
	                zIndex: 10000,
	                helper: function (event) {
	                    var $this = jQuery(this);
	                    return jQuery("<div/>").addClass("mp-obj-helper mp-obj-type" + $this.data("scheme").type).text(jQuery(this).text());
	                }
	            });
	        });

	        this.stage.droppable({
	            activeClass: "ui-custom-highlight",
	            hoverClass: "ui-state-highlight",
	            accept: ".mp-draggable.mp-objects li",
	            drop: function (event, ui) {
	                jQuery(this).data("mp-manager")._appendObject(this, ui);
	                jQuery(this).trigger('appendObject');
	            }
	        });

	        jQuery(".mp-draggable.mp-guests li").each(function () {
	            jQuery(this).draggable({
	                revert: "invalid",
	                revertDuration: 200,
	                cursor: "move",
	                appendTo: "body",
	                cursorAt: { left: 10, top: 5 },
	                zIndex: 10000,
	                helper: function (event) { return jQuery("<p/>").addClass("ui-state-default").text(jQuery(this).text()); }
	            });
	        });

	        jQuery(".mp-droppable.mp-guests").droppable({
	            activeClass: "ui-custom-highlight",
	            hoverClass: "ui-state-highlight",
	            accept: ".mp-draggable-guest",
	            drop: function (event, ui) {
	                jQuery(".mp-toolbar").data("mp-manager")._revertGuest(this, ui);
	            }
	        });
	    },

	    serialize: function () {
	        var data = [];
	        var _manager = this;
	        this.stage.children(".mp-obj").each(function () {
	            var _obj = _manager._serializeObject(jQuery(this));
	            data.push(_obj);
	        });
	        return data;
	    },

	    _serializeObject: function ($obj_container) {
	        var data = {};

	        data = $obj_container.data("scheme");
	        data.position = $obj_container.position();
	        data.size = { width: $obj_container.width(), height: $obj_container.height() };
	        data.sits = this._getTableSits($obj_container);

	        data = data.serialize();

	        return data;
	    },

	    processObjects: function (objs) {
	        for (var i = 0; i < objs.length; i++)
	            this._processObject(this.stage, objs[i]);
	    },

	    clearStage: function () {
	        var _manager = this;
	        this.stage.children(".mp-obj").each(function () {
	            _manager._removeObject(jQuery(this));
	        });
	    },

	    _appendObject: function (stage, ui) {
	        var $canvas = jQuery(stage);

	        var _layoutObj = ui.draggable.data("scheme").clone();
	        _layoutObj.position.top = ui.offset.top - $canvas.offset().top + $canvas.scrollTop();
	        _layoutObj.position.left = ui.offset.left - $canvas.offset().left + $canvas.scrollLeft();

	        var data = _layoutObj.serialize();

	        this._processObject(stage, data);
	    },

	    _processObject: function (stage, data) {
	        var $canvas = jQuery(stage);

	        var _layoutObj = MPLayoutObject.prototype.deserialize(data);
	        var _top = _layoutObj.position.top;
	        var _left = _layoutObj.position.left;

	        var $obj_container = jQuery("<div/>")
			.data("scheme", _layoutObj)
			.addClass("mp-obj mp-obj" + _layoutObj.type)
			.appendTo($canvas)
			.css("top", _top)
			.css("left", _left);

	        this._renderObject($obj_container);
	        this._processPlaceholders($obj_container);
	        this._renderSits($obj_container);

	        if (!this.viewMode) {
	            this._addObjectActions($obj_container);
	            this._bindObjectEvents($obj_container);
	        }
	    },

	    _renderObject: function ($obj_container) {

	        var layoutObj = $obj_container.data("scheme");

	        if (!empty(layoutObj.size) && !empty(layoutObj.size.width) && !empty(layoutObj.size.height)) {
	            $obj_container
					.css("width", layoutObj.size.width)
					.css("height", layoutObj.size.height);
	        } else if (layoutObj.scheme instanceof Matrix) {
	            $obj_container
					.css("width", layoutObj.scheme.width() * layoutObj.placeSize)
					.css("height", layoutObj.scheme.height() * layoutObj.placeSize);
	        }

	        if (!layoutObj.isRound && layoutObj.isTable) {

	            var $grid = jQuery("<table/>");
	            var grid = [];

	            $obj_container.append($grid);

	            var grid_size = { height: layoutObj.scheme.height(), width: layoutObj.scheme.width() };

	            for (var i = 0; i < grid_size.height; i++) {
	                var $tr = jQuery("<tr/>").appendTo($grid);
	                grid.push([]);
	                for (var j = 0; j < grid_size.width; j++) {
	                    var $td = jQuery("<td/>").appendTo($tr);
	                    grid[i].push($td);

	                    if (layoutObj.scheme.matrix[i][j] == 1) {
	                        $td.css("cursor", "move");
	                        $td.addClass("mp-table mp-handler");

	                        jQuery("<div/>")
								.css("width", layoutObj.placeSize)
								.css("height", layoutObj.placeSize)
								.appendTo($td);

	                        if (typeof (layoutObj.scheme.matrix[i - 1]) == "undefined" || layoutObj.scheme.matrix[i - 1][j] != 1)
	                            $td.addClass("mp-border-top");
	                        if (typeof (layoutObj.scheme.matrix[i][j - 1]) == "undefined" || layoutObj.scheme.matrix[i][j - 1] != 1)
	                            $td.addClass("mp-border-left");
	                        if (typeof (layoutObj.scheme.matrix[i + 1]) == "undefined" || layoutObj.scheme.matrix[i + 1][j] != 1)
	                            $td.addClass("mp-border-bottom");
	                        if (typeof (layoutObj.scheme.matrix[i][j + 1]) == "undefined" || layoutObj.scheme.matrix[i][j + 1] != 1)
	                            $td.addClass("mp-border-right");
	                    }
	                }
	            }


	            var _placeholders = layoutObj.getPlaceHolders();
	            for (var i = 0; i < _placeholders.length; i++) {
	                var _pos = _placeholders[i];
	                var $place = jQuery("<div/>")
						.css("widht", layoutObj.placeSize)
						.css("height", layoutObj.placeSize)
						.appendTo(grid[_pos.y][_pos.x]);
	                $place.data("position", { y: _pos.y, x: _pos.x });
	                this._addPlaceHolder($obj_container, $place);
	            }

	            var bounds = this._getTableBounds($obj_container);

	            $obj_container
					.css("width", bounds.width)
					.css("height", bounds.height);

	            $grid.css("margin-left", -bounds.left)
					.css("margin-top", -bounds.top);

	        } else if (layoutObj.isRound && layoutObj.isTable) {
	            $obj_container.addClass("mp-round");
	            var $rtbl = jQuery("<div/>").addClass("mp-table mp-handler");

	            $obj_container.append($rtbl);

	            var horde = (layoutObj.placeSize + 4);
	            var ang = 2 * Math.PI / layoutObj.scheme;

	            var size = horde / Math.sin(ang / 2) - layoutObj.placeSize - 2;
	            size = Math.max(layoutObj.placeSize * 3 / 2, size);

	            $rtbl.css("width", size).css("height", size);

	            var r = (size + 4 + layoutObj.placeSize + 2) / 2 + 2;

	            var curAngle = 0;
	            var position = 0;
	            var count = layoutObj.scheme;
	            do {
	                var x = r * Math.cos(curAngle) - (layoutObj.placeSize + 2) / 2 + (size) / 2;
	                var y = r * Math.sin(curAngle) - (layoutObj.placeSize + 2) / 2 + (size) / 2;

	                var $place = jQuery("<div/>").appendTo($obj_container);
	                $place
						.data("position", position)
						.css("position", "absolute")
						.css("top", y)
						.css("left", x);
	                this._addPlaceHolder($obj_container, $place);

	                curAngle += ang;
	                position++;
	                count--;
	            } while (count > 0)

	            $obj_container
					.css("width", "auto")
					.css("height", "auto");

	        } else if (!layoutObj.isRound && !layoutObj.isTable) {
	            $obj_container.addClass("mp-stage mp-handler")
				.css("cursor", "move");

	        } else {
	            $obj_container.addClass("mp-stage mp-round mp-handler")
				.css("cursor", "move");
	        };

	    },

	    _bindObjectEvents: function ($obj_container) {
	        var layoutObj = $obj_container.data("scheme");

	        $obj_container
			.hover(function (event) { jQuery(this).find(".mp-obj-actions").show(); }, function (event) { jQuery(this).find(".mp-obj-actions").hide(); })
			.draggable({
			    stack: ".mp-obj",
			    handle: ".mp-handler",
			    containment: this.stage,
			    stop: function (event, ui) {
			        jQuery(this).data("position", ui.position);
			    }
			});

	        if (!layoutObj.isTable) {
	            $obj_container.resizable({
	                minWidth: 10, //layoutObj.placeSize * layoutObj.scheme.width(),
	                minHeight: 10//layoutObj.placeSize * layoutObj.scheme.height()
	            });
	        };
	    },

	    // add classes for placeholder blocks
	    _processPlaceholders: function ($obj_container) {
	        var layoutObj = $obj_container.data("scheme");

	        if (layoutObj.isTable && !layoutObj.isRound) {

	            var grid = this._getTableGrid($obj_container);
	            $obj_container.find(".mp-place-holder").each(function () {
	                var $this = jQuery(this);
	                var pos = $this.data("position");
	                if (typeof (grid[pos.y + 1]) != "undefined" && grid[pos.y + 1][pos.x].hasClass("mp-table")) {
	                    $this.addClass("mp-table-down");
	                } else if (typeof (grid[pos.y + 1]) != "undefined" && grid[pos.y + 1][pos.x].find(".mp-place-holder").length) {
	                    $this.addClass("mp-placeholder-down");
	                } else if (typeof (grid[pos.y + 1]) == "undefined" || !grid[pos.y + 1][pos.x].find(".mp-place-holder").length) {
	                    $this.addClass("mp-empty-down");
	                }

	                if (typeof (grid[pos.y - 1]) != "undefined" && grid[pos.y - 1][pos.x].hasClass("mp-table")) {
	                    $this.addClass("mp-table-up");
	                } else if (typeof (grid[pos.y - 1]) != "undefined" && grid[pos.y - 1][pos.x].find(".mp-place-holder").length) {
	                    $this.addClass("mp-placeholder-up");
	                } else if (typeof (grid[pos.y - 1]) == "undefined" || !grid[pos.y - 1][pos.x].find(".mp-place-holder").length) {
	                    $this.addClass("mp-empty-up");
	                }

	                if (typeof (grid[pos.y][pos.x + 1]) != "undefined" && grid[pos.y][pos.x + 1].hasClass("mp-table")) {
	                    $this.addClass("mp-table-right");
	                } else if (typeof (grid[pos.y][pos.x + 1]) != "undefined" && grid[pos.y][pos.x + 1].find(".mp-place-holder").length) {
	                    $this.addClass("mp-placeholder-right");
	                } else if (typeof (grid[pos.y][pos.x + 1]) == "undefined" || !grid[pos.y][pos.x + 1].find(".mp-place-holder").length) {
	                    $this.addClass("mp-empty-right");
	                }

	                if (typeof (grid[pos.y][pos.x - 1]) != "undefined" && grid[pos.y][pos.x - 1].hasClass("mp-table")) {
	                    $this.addClass("mp-table-left");
	                } else if (typeof (grid[pos.y][pos.x - 1]) != "undefined" && grid[pos.y][pos.x - 1].find(".mp-place-holder").length) {
	                    $this.addClass("mp-placeholder-left");
	                } else if (typeof (grid[pos.y][pos.x - 1]) == "undefined" || !grid[pos.y][pos.x - 1].find(".mp-place-holder").length) {
	                    $this.addClass("mp-empty-left");
	                }
	            });
	        } else if (layoutObj.isTable && layoutObj.isRound) {

	            var count = layoutObj.scheme;
	            var step = 360 / count;
	            var ang = 0;
	            $obj_container.find(".mp-place-holder").each(function () {
	                var $this = jQuery(this);
	                $this.css("vertical-align", "middle");
	                var delta = 0;

	                if (ang >= 90 && ang < 270) {
	                    $this.css("direction", "rtl");
	                    delta = 180;
	                }

	                if (count > 5) {
	                    $this
							.css("-webkit-transform", "rotate(" + (delta + ang) + "deg)")
							.css("-moz-transform", "rotate(" + (delta + ang) + "deg)")
							.css("-o-transform", "rotate(" + (delta + ang) + "deg)")
							.css("-ms-transform", "rotate(" + (delta + ang) + "deg)");
	                }
	                ang += step;
	            });
	        }
	    },

	    _getTableGrid: function ($obj_container) {
	        var $grid = $obj_container.children("table");
	        var grid = [];

	        $grid.children("tbody").children().each(function () {
	            grid.push([]);
	            jQuery(this).children().each(function () {
	                grid[grid.length - 1].push(jQuery(this));
	            });

	        });

	        return grid;
	    },

	    _getTableBounds: function ($obj_container) {

	        if (!empty($obj_container.data("bounds")))
	            return $obj_container.data("bounds");

	        var bounds = $obj_container.data("scheme").getTableBounds();
	        var cellWidth = $obj_container.find("table td").eq(0).width();
	        var cellHeight = $obj_container.find("table td").eq(0).height();

	        bounds.left *= cellWidth;
	        bounds.top *= cellHeight;
	        bounds.width *= cellWidth;
	        bounds.height *= cellHeight;

	        $obj_container.data("bounds", bounds);

	        return bounds;
	    },

	    _getTableBiggestArea: function ($obj_container) {

	        if (!empty($obj_container.data("area")))
	            return $obj_container.data("area");

	        var area = $obj_container.data("scheme").getTableBiggestArea();
	        var cellWidth = $obj_container.find("table td").eq(0).width();
	        var cellHeight = $obj_container.find("table td").eq(0).height();

	        area.left *= cellWidth;
	        area.top *= cellHeight;
	        area.width *= cellWidth;
	        area.height *= cellHeight;

	        $obj_container.data("area", area);

	        return area;
	    },

	    _addObjectActions: function ($obj_container) {
	        var layoutObj = $obj_container.data("scheme");

	        var $area = $obj_container;

	        if (layoutObj.isTable && !layoutObj.isRound) {
	            var area = this._getTableBiggestArea($obj_container);
	            var bounds = this._getTableBounds($obj_container);

	            $area = jQuery("<div/>").addClass("mp-obj-area mp-handler")
							.css("position", "absolute")
							.css("left", area.left - bounds.left)
							.css("top", area.top - bounds.top)
							.css("width", area.width)
							.css("height", area.height);

	            $obj_container.append($area);
	        }

	        var $title = jQuery("<span/>")
				.addClass("mp-obj-title")
				.text(layoutObj.title)
				.css("top", "50%")
				.css("width", "100%")
				.css("text-align", "center")
				.css("position", "absolute");

	        if (layoutObj.isTable)
	            $title.addClass("mp-handler");

	        $area.append($title);

	        $title
				.css("margin-top", -$title.height() / 2);

	        var $actions_div = jQuery("<div/>").addClass("mp-obj-actions")
				.css("position", "absolute")
				.css("white-space", "nowrap")
				.css("left", "50%")
				.css("top", "2px").hide();

	        if (layoutObj.isRound && layoutObj.isTable) {

	            jQuery("<button class=\"ui-state-default ui-corner-all\" title=\"" + this._('ACTION_ENCREASE') + "\"><span class=\"ui-icon ui-icon-plus\"></span></button>").appendTo($actions_div)
					.click(function (event) { var $obj = jQuery(this).closest(".mp-obj"); jQuery(".mp-canvas").data("mp-manager")._resizeObject($obj, $obj.data("scheme").scheme + 1); });
	            jQuery("<button class=\"ui-state-default ui-corner-all\" title=\"" + this._('ACTION_REDUCE') + "\"><span class=\"ui-icon ui-icon-minus\"></span></button>").appendTo($actions_div)
					.click(function (event) { var $obj = jQuery(this).closest(".mp-obj"); jQuery(".mp-canvas").data("mp-manager")._resizeObject($obj, $obj.data("scheme").scheme - 1); });
	        }

	        if (!layoutObj.isRound && layoutObj.isTable) {

	            if (layoutObj._getTableResizers(true).length > 0) {
	                jQuery("<button class=\"ui-state-default ui-corner-all\" title=\"" + this._('ACTION_REDUCE_V') + "\"><span class=\"ui-icon ui-icon-arrowstop-1-n\"></span></button>").appendTo($actions_div)
						.click(function (event) { var $obj = jQuery(this).closest(".mp-obj"); jQuery(".mp-canvas").data("mp-manager")._resizeObject($obj, { width: $obj.data("scheme").scheme.width(), height: $obj.data("scheme").scheme.height() - 1 }); });

	                jQuery("<button class=\"ui-state-default ui-corner-all\" title=\"" + this._('ACTION_ENCREASE_V') + "\"><span class=\"ui-icon ui-icon-arrowstop-1-s\"></span></button>").appendTo($actions_div)
						.click(function (event) { var $obj = jQuery(this).closest(".mp-obj"); jQuery(".mp-canvas").data("mp-manager")._resizeObject($obj, { width: $obj.data("scheme").scheme.width(), height: $obj.data("scheme").scheme.height() + 1 }); });
	            }

	            if (layoutObj._getTableResizers().length > 0) {
	                jQuery("<button class=\"ui-state-default ui-corner-all\" title=\"" + this._('ACTION_REDUCE_H') + "\"><span class=\"ui-icon ui-icon-arrowstop-1-w\"></span></button>").appendTo($actions_div)
						.click(function (event) { var $obj = jQuery(this).closest(".mp-obj"); jQuery(".mp-canvas").data("mp-manager")._resizeObject($obj, { width: $obj.data("scheme").scheme.width() - 1, height: $obj.data("scheme").scheme.height() }); });

	                jQuery("<button class=\"ui-state-default ui-corner-all\" title=\"" + this._('ACTION_ENCREASE_H') + "\"><span class=\"ui-icon ui-icon-arrowstop-1-e\"></span></button>").appendTo($actions_div)
						.click(function (event) { var $obj = jQuery(this).closest(".mp-obj"); jQuery(".mp-canvas").data("mp-manager")._resizeObject($obj, { width: $obj.data("scheme").scheme.width() + 1, height: $obj.data("scheme").scheme.height() }); });
	            }
	        }

	        jQuery("<button class=\"ui-state-default ui-corner-all\" title=\"" + this._('ACTION_EDIT') + "\"><span class=\"ui-icon ui-icon-pencil\"></span></button>").appendTo($actions_div)
				.click(function (event) { var $obj = jQuery(this).closest(".mp-obj"); jQuery(".mp-canvas").data("mp-manager")._editObject($obj); });

	        if (!layoutObj.isRound && layoutObj.isTable) {
	            jQuery("<button class=\"ui-state-default ui-corner-all\" title=\"" + this._('ACTION_ROTATE') + "\"><span class=\"ui-icon ui-icon-arrowrefresh-1-e\"></span></button>").appendTo($actions_div)
					.click(function (event) { var $obj = jQuery(this).closest(".mp-obj"); jQuery(".mp-canvas").data("mp-manager")._rotateObject($obj); });
	        }

	        jQuery("<button class=\"ui-state-default ui-corner-all\" title=\"" + this._('ACTION_DELETE') + "\"><span class=\"ui-icon ui-icon-trash\"></span></button>").appendTo($actions_div)
				.click(function (event) { if (confirm(jQuery(".mp-canvas").data("mp-manager")._('ACTION_DELETE_CONFIRM'))) { var $obj = jQuery(this).closest(".mp-obj"); jQuery(".mp-canvas").data("mp-manager")._removeObject($obj); } });

	        $area.append($actions_div);
	        $actions_div
				.css("margin-left", -$actions_div.width() / 2);
	    },


	    _editObject: function ($obj_container) {
	        var layoutObj = $obj_container.data("scheme");

	        var $dialog = jQuery("<div title=\'" + this._('ACTION_EDIT') + "\'/>").addClass("mp-obj-dialog");
	        var $tbl = jQuery("<table/>").appendTo($dialog);

	        $tbl.append("<tr><td><label>" + this._('TITLE') + ": </label></td><td><input type=\'text\' name=\'title\'/></td</tr>");

	        if (layoutObj.isTable && layoutObj.isRound)
	            $tbl.append("<tr><td><label>" + this._('PLACE_COUNT') + ": </label></td><td><input type=\'number\' min=\'2\' name=\'places\'/></td></tr>");

	        $dialog.find("input[name=title]").val(layoutObj.title);
	        $dialog.find("input[name=places]").val(this._getTableSits($obj_container).length);

	        $dialog.dialog({
	            resizable: false,
	            modal: true,
	            buttons: {
	                "Применить": function () {
	                    var manager = jQuery(".mp-canvas").data("mp-manager");
	                    layoutObj.title = jQuery(this).find("input[name=title]").val();
	                    var places = jQuery(this).find("input[name=places]").val();

	                    manager._setTablePlacesCount($obj_container, places);

	                    var data = manager._serializeObject($obj_container);
	                    manager._removeObject($obj_container);
	                    manager._processObject(manager.stage, data);

	                    jQuery(this).dialog("close");
	                },
	                "Отмена": function () {
	                    jQuery(this).dialog("close");
	                }
	            }
	        });

	    },

	    _setTablePlacesCount: function ($obj_container, count) {
	        var layoutObj = $obj_container.data("scheme");

	        if (layoutObj.isTable && layoutObj.isRound) {
	            layoutObj.scheme = Math.max(count, 2);
	        }

	        console.log(count);
	    },

	    _bringToFront: function ($obj) {
	        var $children = jQuery($obj).parent().children().get();
	        var _max_zIndex = 0;
	        var $_itm = null;

	        jQuery.each($children, function (idx, itm) { _max_zIndex = Math.max(_max_zIndex, parseInt(jQuery(itm).css("z-index"))); });
	        jQuery.each($children, function (idx, itm) { if (_max_zIndex == parseInt(jQuery(itm).css("z-index"))) $_itm = jQuery(itm); });

	        if (!empty($_itm))
	            $_itm.css("z-index", $obj.css("z-index"));
	        $obj.css("z-index", _max_zIndex);
	    },

	    _rotateObject: function ($obj_container) {

	        var layoutObj = $obj_container.data("scheme");
	        layoutObj.sits = this._getTableSits($obj_container);

	        layoutObj.rotateScheme();

	        var data = this._serializeObject($obj_container);
	        data.sits = layoutObj.sits;

	        this._removeObject($obj_container);
	        this._processObject(this.stage, data);
	    },

	    _resizeObject: function ($obj_container, size) {

	        var layoutObj = $obj_container.data("scheme");

	        layoutObj.resizeScheme(size);

	        var data = this._serializeObject($obj_container);

	        this._removeObject($obj_container);
	        this._processObject(this.stage, data);
	    },

	    _removeObject: function ($obj_container) {
	        $obj_container.find(".mp-draggable-guest").each(function () {
	            jQuery(".mp-canvas").data("mp-manager")._revertGuest(".mp-droppable.mp-guests", { draggable: jQuery(this) });
	        });

            if($obj_container.hasClass('ui-draggable'))
                $obj_container.draggable("destroy");

            if($obj_container.hasClass('ui-resizable'))
                $obj_container.resizable("destroy");
                
                $obj_container.remove();
	    },

	    // add placeholder internal dom element
	    _addPlaceHolder: function ($obj_container, $trgt) {
	        $trgt.addClass("mp-place-holder")
			.css("width", $obj_container.data("scheme").placeSize)
			.css("height", $obj_container.data("scheme").placeSize)
			.droppable({
			    activeClass: "ui-custom-highlight",
			    hoverClass: "ui-state-highlight",
			    accept: ".mp-draggable-guest",
			    drop: function (event, ui) {
			        jQuery(".mp-canvas").data("mp-manager")._takeSit(this, ui);
			    }
			})
	        //.hover(function(){jQuery(".mp-canvas").data("mp-manager")._bringToFront(jQuery(this));})
			;
	    },
	    
	    _getTableSits: function ($obj_container) {
	        var sits = [];
	        $obj_container.find(".mp-place-holder").each(function () {

	            var $guest = jQuery(this).find(".mp-draggable-guest");

	            if ($guest.length) {
	                $guest.data("data").position = jQuery(this).data("position");
	                sits.push($guest.data("data"));
	            } else
	                sits.push(null);
	        });
	        return sits;
	    },

	    _renderSits: function ($obj_container) {
	        var layoutObj = $obj_container.data("scheme");
	        var sits = jQuery.extend([], $obj_container.data("scheme").sits);
	        var $guests = jQuery(".mp-toolbar .mp-guests").find("li.mp-draggable-guest");

	        for (var i = 0; i < sits.length; i++) {
	            var exists = false;
	            for (var j = 0; j < $guests.length; j++) {
	                if (sits[i] != null && jQuery($guests[j]).data("data").id == sits[i].id) {
	                    exists = true;
	                    jQuery($guests[j]).data("data").position = sits[i].position;
	                    sits[i] = jQuery($guests[j]);
	                    break;
	                }
	            }

	            if (!exists) {
	                sits[i] = null;
	            }
	        }

	        if (layoutObj.isTable && !layoutObj.isRound) {
	            var grid = this._getTableGrid($obj_container);
	            for (var i = 0; i < sits.length; i++) {
	                if (sits[i] != null) {
	                    var _pos = sits[i].data("data").position;
	                    if (!empty(grid[_pos.y][_pos.x]))
	                        this._takeSit(grid[_pos.y][_pos.x].find(".mp-place-holder"), { draggable: sits[i] });
	                }
	            }
	        } else {
	            var i = 0;
	            $obj_container.find(".mp-place-holder").each(function () {
	                if (sits[i] != null)
	                    jQuery(".mp-canvas").data("mp-manager")._takeSit(this, { draggable: sits[i] });
	                i++;
	            });
	        }
	    },

	    _takeSit: function (placeholder, ui) {
	        ui.draggable.appendTo(placeholder).css("left", 0).css("top", 0).css("position", "relative");
	    },

	    _revertGuest: function (trgt, ui) {
	        ui.draggable.appendTo(jQuery(trgt).find("ul")).css("left", 0).css("top", 0).css("position", "relative");
	        this._sortGuests();
	    }
	};
	
//})(jQuery);